﻿using System.Linq;
using CID.Domain.Development;
using CID.Tests.Support;
using NUnit.Framework;

namespace CID.Domain.Persistence.Tests.Development
{
    [TestFixture]
    class VersionPersistenceTests : BasePersistenceWithDataTests
    {
        private void AssertAreEqual(IVersion expected, Version actual)
        {
            var expectedPackagesID = expected.Packages.Select(x => x.Id).ToArray();
            var actualPackagesID = actual.Packages.Select(x => x.Id).ToArray();
            var expectedDependenciesID = expected.DependsOn.Select(x => x.Id).ToArray();
            var actualDependenciesID = actual.DependsOn.Select(x => x.Id).ToArray();
            int? expectedActivePackageID = (expected.ActivePackage != null) ? expected.ActivePackage.Id : new int?();
            int? actualActivePackageID = (actual.ActivePackage != null) ? actual.ActivePackage.Id : new int?();

            Assert.AreEqual(expected.Id, actual.Id);
            Assert.AreEqual(expected.Component.Id, actual.Component.Id);
            Assert.AreEqual(expected.Name, actual.Name);
            Assert.AreEqual(expected.Description, actual.Description);
            Assert.AreEqual(expected.DeploymentDefinition.Id, actual.DeploymentDefinition.Id);
            Assert.AreEqual(expectedActivePackageID, actualActivePackageID);
            CollectionAssert.AreEquivalent(expectedDependenciesID, actualDependenciesID);
            CollectionAssert.AreEquivalent(expectedPackagesID, actualPackagesID);
        }

        [Test]
        public void PersistNewVersion_VersionShouldBeSaved()
        {
            var session = OpenSession();
            var component = DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1);
            var newVersion = component.CreateVersion(GetRandomString(), GetRandomString());
            var dependencyComponent = DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1, "Dependency component");
            var packageType = Infrastructure.DataProvider.GetPackageType(session, InfrastructureData.PackageType);
            var package1 = Infrastructure.DataProvider.CreatePackage(packageType, newVersion, new byte[] { 1, 2, 3 }, "First Package");
            var package2 = Infrastructure.DataProvider.CreatePackage(packageType, newVersion, new byte[] { 3, 2, 1 }, "Second Package");
            newVersion.SetActivePackage(package2);
            newVersion.AddDependency(dependencyComponent);
            session.SaveOrUpdate(component);
            session.SaveOrUpdate(dependencyComponent);
            CleanSession(session);

            Assert.AreNotEqual(NotSavedId, newVersion.Id);
            session = OpenSession();
            var retrievedVersion = session.Get<Version>(newVersion.Id);
            AssertAreEqual(newVersion, retrievedVersion);
            CleanSession(session);
        }

        [Test]
        public void PersistModifiedVersion_ChangesShouldBeSaved()
        {
            var session = OpenSession();
            var component = DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1);
            var newVersion = component.CreateVersion(GetRandomString(), GetRandomString());
            var dependencyComponent = DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1, "Dependency component");
            var packageType = Infrastructure.DataProvider.GetPackageType(session, InfrastructureData.PackageType);
            var package1 = Infrastructure.DataProvider.CreatePackage(packageType, newVersion, new byte[] { 1, 2, 3 }, "First Package");
            var package2 = Infrastructure.DataProvider.CreatePackage(packageType, newVersion, new byte[] { 3, 2, 1 }, "Second Package");
            newVersion.SetActivePackage(package2);
            newVersion.AddDependency(dependencyComponent);
            session.SaveOrUpdate(component);
            session.SaveOrUpdate(dependencyComponent);
            CleanSession(session);

            session = OpenSession(); 
            var modifiedVersion = session.Get<Version>(newVersion.Id);
            AssertAreEqual(newVersion, modifiedVersion); //Necessary to get lazy collections before the session gets cleaned
            dependencyComponent = session.Get<Component>(dependencyComponent.Id);
            modifiedVersion.RemoveDepedency(dependencyComponent);
            dependencyComponent = DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1, "Another dependecy component");
            modifiedVersion.AddDependency(dependencyComponent);
            modifiedVersion.ModifyProperty(x => x.Name);
            modifiedVersion.ModifyProperty(x => x.Description);
            packageType = Infrastructure.DataProvider.GetPackageType(session, InfrastructureData.PackageType);
            var package3 = Infrastructure.DataProvider.CreatePackage(packageType, modifiedVersion, new byte[] { 2, 1, 3 }, "Third Package");
            modifiedVersion.SetActivePackage(package3);
            session.SaveOrUpdate(dependencyComponent);
            session.SaveOrUpdate(modifiedVersion);
            CleanSession(session);

            session = OpenSession();
            var retrievedVersion = session.Get<Version>(newVersion.Id);
            AssertAreEqual(modifiedVersion, retrievedVersion);
            CleanSession(session);
        }

        [Test]
        public void DeleteVersion_VersionShouldBeDeleted()
        {
            var session = OpenSession();
            var component = DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1);
            var newVersion1 = component.CreateVersion(GetRandomString(), GetRandomString());
            var newVersion2 = component.CreateVersion(GetRandomString(), GetRandomString());
            var dependencyComponent = DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1, "Dependency component");
            var packageType = Infrastructure.DataProvider.GetPackageType(session, InfrastructureData.PackageType);
            var package1 = Infrastructure.DataProvider.CreatePackage(packageType, newVersion1, new byte[] { 1, 2, 3 }, "First Package");
            var package2 = Infrastructure.DataProvider.CreatePackage(packageType, newVersion1, new byte[] { 3, 2, 1 }, "Second Package");
            newVersion1.SetActivePackage(package2);
            newVersion1.AddDependency(dependencyComponent);
            session.SaveOrUpdate(component);
            session.SaveOrUpdate(dependencyComponent);
            CleanSession(session);

            session = OpenSession();
            var retrievedComponent = session.Get<Component>(component.Id);
            retrievedComponent.RemoveVersion(retrievedComponent.Versions.Single(x=>x.Id.Equals(newVersion1.Id)));
            session.SaveOrUpdate(retrievedComponent);
            CleanSession(session);

            session = OpenSession();
            var retrievedVersion1 = session.Get<Version>(newVersion1.Id);
            var retrievedVersion2 = session.Get<Version>(newVersion2.Id);
            Assert.IsNull(retrievedVersion1);
            Assert.IsNotNull(retrievedVersion2);
            CleanSession(session);
        }
    }
}
